function varargout = tolerance(This,varargin)
% tolerance  Get or set model-specific tolerance levels.
%
%
% Syntax for getting tolerance
% =============================
%
%     TolStruct = tolerance(M)
%     Tol = tolerance(M,Scope)
%
%
% Syntax for setting tolerance
% =============================
%
%     M = tolerance(M,TolStruct)
%     M = tolerance(M,@default)
%     M = tolerance(M,Scope,Tol)
%     M = tolerance(M,Scope,@default)
%
%
% Input arguments
% ================
%
% * `M` [ model ] - Model object.
%
% * `Scope` [ `'solve'` | `'steady'` | `'eigen'` | `'mse'` ] - Scope
% in which the new tolerance level will be used.
%
% * `Tol` [ numeric ] - New tolerance level used to detect singularities
% and unit roots; if `@default` tolerance will be set to its default value.
%
% * `TolStruct` [ numeric ] - Structure with new levels of tolerance for
% each scope.
%
%
% Output arguments
% =================
%
% * `Tol` [ numeric ] - Currently assigned level of tolerance.
%
% * `TolStruct` [ numeric ] - Structure with currently assigned levels of
% tolerance for each scope.
%
% * `M` [ model ] - Model object with the new level of tolerance set.
%
%
% Description
% ============
%
%

% -IRIS Toolbox.
% -Copyright (c) 2007-2015 IRIS Solutions Team.

%--------------------------------------------------------------------------

if nargin==1
    % Get tolerance:
    % TolStruct = tolerance(M)
    varargout{1} = This.Tolerance;
    return
end

if nargin==2 && isstruct(varargin{1}) ...
        && isfield(varargin{1},'Solve') ...
        && isfield(varargin{1},'Eigen') ...
        && isfield(varargin{1},'Steady') ...
        && isfield(varargin{1},'Mse')
    % Set tolerance:
    % M = tolerance(M,TolStruct)
    This.Tolerance.Solve =  varargin{1}.Solve;
    This.Tolerance.Eigen =  varargin{1}.Eigen;
    This.Tolerance.Steady = varargin{1}.Steady;
    This.Tolerance.Mse =    varargin{1}.Mse;
    varargout{1} = This;
    return
end

if nargin==2 && isequal(varargin{1},@default)
    % Set tolerance:
    % M = tolerance(M,@default)
    This.Tolerance = model.DEFAULT_TOLERANCE_STRUCT;
    varargout{1} = This;
    return
end
    
Scope = varargin{1};
switch lower(Scope)
    case {'solution', 'solve'}
        Scope = 'Solve';
        def = model.DEFAULT_SOLVE_TOLERANCE;
    case {'eigen', 'unitroot'}
        Scope = 'Eigen';
        def = model.DEFAULT_EIGEN_TOLERANCE;
    case {'steady', 'steadystate', 'sstate'}
        Scope = 'Steady';
        def = model.DEFAULT_STEADY_TOLERANCE;
    case {'mse'}
        Scope = 'Mse';
        def = model.DEFAULT_MSE_TOLERANCE;
    otherwise
        utils.error('model:tolerance', ...
            'Invalid tolerance scope');
end

if nargin==2
    % Get tolerance:
    % Tol = tolerance(M,Scope)
    varargout{1} = This.Tolerance.(Scope);
    return
end

if nargin==3
    Tol = varargin{2};
    if isnumericscalar(Tol) && Tol>0
        % Set tolerance:
        % M = tolerance(M,Scope,Tol)
        This.Tolerance.(Scope) = Tol;
    elseif isequal(Tol,@default)
        % Set tolerance:
        % M = tolerance(M,Scope,@default)        
        This.Tolerance.(Scope) = def;
    else
        utils.error('model:tolerance', ...
            'Tolerance level must be positive scalar');
    end
    varargout{1} = This;
    return
end

end
